/**
 * OpenAI客户端封装
 * 负责与OpenAI API的通信
 */

import {
  OpenAIClientConfig,
  AICompletionRequest,
  AICompletionResponse,
  AIResult,
  AIError,
  AIErrorCode
} from './types'
import { electronFetch } from './electronFetch'

export class OpenAIClient {
  private config: OpenAIClientConfig

  constructor(config: OpenAIClientConfig) {
    this.config = {
      model: 'gpt-3.5-turbo',
      baseURL: 'https://api.openai.com/v1',
      timeout: 30000,
      maxRetries: 3,
      ...config
    }
  }

  /**
   * 获取可用模型列表
   */
  async getModels(): Promise<AIResult<Array<{ id: string; object: string; created: number }>>> {
    if (!this.config.apiKey) {
      return {
        ok: false,
        error: {
          code: AIErrorCode.API_KEY_MISSING,
          message: 'API密钥未配置'
        }
      }
    }

    if (!this.config.baseURL) {
      console.error('[OpenAI] baseURL未配置')
      return {
        ok: false,
        error: {
          code: AIErrorCode.INVALID_REQUEST,
          message: 'API端点未配置'
        }
      }
    }

    try {
      const modelsUrl = `${this.config.baseURL}/models`
      console.log('[OpenAI] 获取模型列表', {
        baseURL: this.config.baseURL,
        fullUrl: modelsUrl,
        hasApiKey: !!this.config.apiKey,
        apiKeyPrefix: this.config.apiKey?.substring(0, 10) + '...'
      })

      const controller = new AbortController()
      const timeoutId = setTimeout(() => controller.abort(), 10000)

      const response = await electronFetch(modelsUrl, {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${this.config.apiKey}`
        },
        signal: controller.signal
      })

      clearTimeout(timeoutId)

      console.log('[OpenAI] 模型API响应', {
        status: response.status,
        statusText: response.statusText,
        ok: response.ok
      })

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}))
        console.error('[OpenAI] 模型API错误', { status: response.status, errorData })
        throw {
          status: response.status,
          statusText: response.statusText,
          data: errorData
        }
      }

      const data = await response.json()
      console.log('[OpenAI] 模型列表获取成功', {
        count: data.data?.length || 0
      })

      return {
        ok: true,
        data: data.data || []
      }
    } catch (error: any) {
      console.error('[OpenAI] 获取模型列表失败', {
        name: error?.name,
        message: error?.message,
        code: error?.code,
        stack: error?.stack
      })
      return {
        ok: false,
        error: this.handleError(error)
      }
    }
  }

  /**
   * 获取用户信息(余额等)
   * 仅支持硅基流动等提供此API的服务商
   */
  async getUserInfo(): Promise<AIResult<{ balance: string; totalBalance: string }>> {
    if (!this.config.apiKey) {
      return {
        ok: false,
        error: {
          code: AIErrorCode.API_KEY_MISSING,
          message: 'API密钥未配置'
        }
      }
    }

    if (!this.config.baseURL) {
      console.error('[OpenAI] baseURL未配置')
      return {
        ok: false,
        error: {
          code: AIErrorCode.INVALID_REQUEST,
          message: 'API端点未配置'
        }
      }
    }

    try {
      const userInfoUrl = `${this.config.baseURL}/user/info`
      console.log('[OpenAI] 获取用户信息', {
        baseURL: this.config.baseURL,
        fullUrl: userInfoUrl
      })

      const controller = new AbortController()
      const timeoutId = setTimeout(() => controller.abort(), 10000)

      const response = await electronFetch(userInfoUrl, {
        method: 'GET',
        headers: {
          'Authorization': `Bearer ${this.config.apiKey}`
        },
        signal: controller.signal
      })

      clearTimeout(timeoutId)

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}))
        throw {
          status: response.status,
          statusText: response.statusText,
          data: errorData
        }
      }

      const result = await response.json()
      console.log('[OpenAI] 用户信息获取成功')

      return {
        ok: true,
        data: {
          balance: result.data?.balance || '0',
          totalBalance: result.data?.totalBalance || '0'
        }
      }
    } catch (error) {
      console.error('[OpenAI] 获取用户信息失败', error)
      return {
        ok: false,
        error: this.handleError(error)
      }
    }
  }

  /**
   * 测试连接
   * 使用最小的请求测试API配置是否正确
   */
  async testConnection(): Promise<AIResult<{ model: string; message: string }>> {
    // 验证API密钥
    if (!this.config.apiKey) {
      return {
        ok: false,
        error: {
          code: AIErrorCode.API_KEY_MISSING,
          message: 'API密钥未配置'
        }
      }
    }

    try {
      console.log('[OpenAI] 测试连接', {
        baseURL: this.config.baseURL,
        model: this.config.model
      })

      // 使用一个非常小的测试请求
      const response = await this.callOpenAI({
        model: this.config.model!,
        messages: [
          {
            role: 'user',
            content: '测试'
          }
        ],
        max_tokens: 5,
        temperature: 0
      })

      console.log('[OpenAI] 连接测试成功')

      return {
        ok: true,
        data: {
          model: response.model,
          message: '连接成功'
        }
      }
    } catch (error) {
      console.error('[OpenAI] 连接测试失败', error)
      return {
        ok: false,
        error: this.handleError(error)
      }
    }
  }

  /**
   * 调用AI补全接口（续写专用）
   */
  async complete(request: AICompletionRequest): Promise<AIResult<AICompletionResponse>> {
    // 验证API密钥
    if (!this.config.apiKey) {
      return {
        ok: false,
        error: {
          code: AIErrorCode.API_KEY_MISSING,
          message: 'OpenAI API密钥未配置，请在设置中配置'
        }
      }
    }

    // 构建消息
    const messages = [
      {
        role: 'system',
        content: '你是一个专业的写作助手，帮助用户续写文章内容。请保持文风一致，内容连贯自然。'
      },
      {
        role: 'user',
        content: request.prompt
      }
    ]

    try {
      console.log('[OpenAI] 开始调用API', {
        model: this.config.model,
        promptLength: request.prompt.length,
        maxTokens: request.maxTokens || 500
      })

      const response = await this.callOpenAIWithRetry({
        model: this.config.model!,
        messages,
        max_tokens: request.maxTokens || 500,
        temperature: request.temperature || 0.7
      })

      console.log('[OpenAI] API调用成功', {
        contentLength: response.choices[0].message.content.length,
        usage: response.usage
      })

      return {
        ok: true,
        data: {
          content: response.choices[0].message.content,
          usage: response.usage
        }
      }
    } catch (error) {
      console.error('[OpenAI] API调用失败', error)
      return {
        ok: false,
        error: this.handleError(error)
      }
    }
  }

  /**
   * 通用文本生成接口（不添加额外的system消息）
   */
  async generateText(request: AICompletionRequest): Promise<AIResult<AICompletionResponse>> {
    // 验证API密钥
    if (!this.config.apiKey) {
      return {
        ok: false,
        error: {
          code: AIErrorCode.API_KEY_MISSING,
          message: 'OpenAI API密钥未配置，请在设置中配置'
        }
      }
    }

    // 直接使用prompt作为user消息，不添加额外的system消息
    const messages = [
      {
        role: 'user',
        content: request.prompt
      }
    ]

    try {
      console.log('[OpenAI] 开始生成文本', {
        model: this.config.model,
        promptLength: request.prompt.length,
        maxTokens: request.maxTokens || 1000
      })

      // 确保model字段存在（硅基流动等API强制要求）
      const response = await this.callOpenAIWithRetry({
        model: this.config.model!,
        messages,
        max_tokens: request.maxTokens || 1000,
        temperature: request.temperature ?? 0.7
      })

      console.log('[OpenAI] 文本生成成功', {
        contentLength: response.choices[0].message.content.length,
        usage: response.usage
      })

      return {
        ok: true,
        data: {
          content: response.choices[0].message.content,
          usage: response.usage
        }
      }
    } catch (error) {
      console.error('[OpenAI] 文本生成失败', error)
      return {
        ok: false,
        error: this.handleError(error)
      }
    }
  }

  /**
   * 带重试的API调用
   */
  private async callOpenAIWithRetry(params: any, retryCount = 0): Promise<any> {
    try {
      return await this.callOpenAI(params)
    } catch (error: any) {
      // 如果是可重试的错误且未超过重试次数
      if (this.isRetryableError(error) && retryCount < this.config.maxRetries!) {
        console.log(`[OpenAI] 重试 (${retryCount + 1}/${this.config.maxRetries})`)

        // 指数退避
        const delay = Math.pow(2, retryCount) * 1000
        await new Promise(resolve => setTimeout(resolve, delay))

        return this.callOpenAIWithRetry(params, retryCount + 1)
      }

      throw error
    }
  }

  /**
   * 实际的API调用
   */
  private async callOpenAI(params: any): Promise<any> {
    const controller = new AbortController()
    const timeoutId = setTimeout(() => controller.abort(), this.config.timeout!)

    try {
      console.log('[OpenAI] 发起请求', {
        url: `${this.config.baseURL}/chat/completions`,
        model: params.model,
        hasApiKey: !!this.config.apiKey,
        apiKeyPrefix: this.config.apiKey?.substring(0, 10) + '...'
      })

      const response = await electronFetch(`${this.config.baseURL}/chat/completions`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.config.apiKey}`
        },
        body: JSON.stringify(params),
        signal: controller.signal
      })

      clearTimeout(timeoutId)

      console.log('[OpenAI] 收到响应', {
        status: response.status,
        statusText: response.statusText,
        ok: response.ok
      })

      if (!response.ok) {
        const errorData = await response.json().catch(() => ({}))
        console.error('[OpenAI] API返回错误', { status: response.status, errorData })
        throw {
          status: response.status,
          statusText: response.statusText,
          data: errorData
        }
      }

      return await response.json()
    } catch (error: any) {
      clearTimeout(timeoutId)

      console.error('[OpenAI] 请求异常', {
        name: error.name,
        message: error.message,
        code: error.code,
        type: error.type
      })

      if (error.name === 'AbortError') {
        throw { code: 'ETIMEDOUT', message: '请求超时' }
      }

      // 网络错误(fetch失败)
      if (error instanceof TypeError && error.message.includes('fetch')) {
        throw {
          code: 'NETWORK_ERROR',
          message: '网络连接失败: ' + error.message,
          originalError: error
        }
      }

      throw error
    }
  }

  /**
   * 判断错误是否可重试
   */
  private isRetryableError(error: any): boolean {
    // 网络错误可重试
    if (error.code === 'ECONNABORTED' || error.code === 'ETIMEDOUT') {
      return true
    }

    // 429 限流错误可重试
    if (error.status === 429) {
      return true
    }

    // 5xx 服务器错误可重试
    if (error.status >= 500 && error.status < 600) {
      return true
    }

    return false
  }

  /**
   * 错误处理
   */
  private handleError(error: any): AIError {
    // API密钥无效
    if (error.status === 401) {
      return {
        code: AIErrorCode.API_KEY_INVALID,
        message: 'API密钥无效，请检查配置',
        details: error.data
      }
    }

    // 限流
    if (error.status === 429) {
      return {
        code: AIErrorCode.RATE_LIMIT,
        message: '请求过于频繁，请稍后再试',
        details: error.data
      }
    }

    // 配额超限
    if (error.status === 429 && error.data?.error?.type === 'insufficient_quota') {
      return {
        code: AIErrorCode.QUOTA_EXCEEDED,
        message: 'API配额已用尽，请检查账户余额',
        details: error.data
      }
    }

    // 无效请求
    if (error.status === 400) {
      return {
        code: AIErrorCode.INVALID_REQUEST,
        message: '请求参数无效',
        details: error.data
      }
    }

    // 超时
    if (error.code === 'ETIMEDOUT') {
      return {
        code: AIErrorCode.TIMEOUT,
        message: '请求超时，请检查网络连接',
        details: error
      }
    }

    // 网络错误
    if (!error.status) {
      return {
        code: AIErrorCode.NETWORK_ERROR,
        message: '网络连接失败，请检查网络设置',
        details: error
      }
    }

    // 未知错误
    return {
      code: AIErrorCode.UNKNOWN,
      message: error.message || '未知错误',
      details: error
    }
  }
}
